package view;

import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

import org.bushe.swing.event.EventSubscriber;
import org.bushe.swing.event.annotation.EventTopicPatternSubscriber;
import org.bushe.swing.event.annotation.EventTopicSubscriber;

import model.IModel;
import core.EventBus;

//import model.TurnTimer;

/**
 * This code was edited or generated using CloudGarden's Jigloo
 * SWT/Swing GUI Builder, which is free for non-commercial
 * use. If Jigloo is being used commercially (ie, by a corporation,
 * company or business for any purpose whatever) then you
 * should purchase a license for each developer using Jigloo.
 * Please visit www.cloudgarden.com for details.
 * Use of Jigloo implies acceptance of these licensing terms.
 * A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
 * THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
 * LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
 */
public class View extends JFrame implements PropertyChangeListener, EventSubscriber<IModel>{
	private static final long serialVersionUID = 1L;

	//Menu-related variables
	private JMenuBar menuBar;
	private JMenu menu;
	private JMenu menuSound;
	private JMenu menuHelp;
	private JMenu menuSettings;
	private JMenuItem menuNewGame;
	private JMenuItem menuNetwork;
	private JMenuItem menuSave;
	private JMenuItem menuLoad;
	private AbstractAction rulesButtonAction;
	private JMenuItem rulesButton;
	private JLabel labelTime;
	private AbstractAction highScoreButtonAction;
	private AbstractAction actionThrow;
	private JMenuItem buttonViewHighScore;
	private JMenu menuHighScore;
	private JMenuItem exitButton;
	private JMenuItem menuItemShowHelp;
	private JMenuItem menuItemAbout;
	private JCheckBoxMenuItem menuMusic;
	private JCheckBoxMenuItem menuFX;
	private JSeparator menuSeparator1;
	private JSeparator menuSeparator2;
	private AbstractAction exitAction;
	private AbstractAction menuAboutAction;
	private AbstractAction menuHelpAction;
	private AbstractAction abstractNewGame;
	private AbstractAction playerButtonAction;
	private JMenuItem playerButton;
	
	
	//Important gameplay related variables
	private JTextField txtDie; //Show the result of a die throw
	private JTextField txtTurn;//Who's turn is it?
	private JTextField txtTime;//Play your turn before the time runs out.

	//Other variables
	private DieButton btnDie;
	private JLabel lblDie;
	private JLabel lblTurn;
	private JLabel lblP4;
	private JLabel lblP3;
	private JLabel lblP2;
	private JLabel lblP1;
	private StartBox panelP3;
	private StartBox panelP2;
	private StartBox panelP4;
	private StartBox panelP1;
	private EventBus m;
	private PlayerSettings pSettings;

	//private TurnTimer timer = new TurnTimer(this, 2000);
	//private State state = State.getInstance();


	public View(EventBus e) {
		this.m = e;
		org.bushe.swing.event.EventBus.subscribe(model.TurnTimer.class, this);
		pSettings = new PlayerSettings(m);
		m.addPropertyChangeListener(this);
		initGUI();	
		initSquares();
		repaint();
	}	

	/**
	 * Initiate the View, which is the main graphical form for Ludo3k.
	 */
	private void initGUI() {
		try {
			{
				getContentPane().setLayout(null);
				getContentPane().setBackground(new java.awt.Color(255,255,255));
				this.setTitle("Ludo 3K");
				this.setResizable(false);
				this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				{
					menuBar = new JMenuBar();
					setJMenuBar(menuBar);
					{
						menu = new JMenu();
						menuBar.add(menu);
						menuBar.add(getMenuSettings());
						menuBar.add(getMenuHelp());
						menuBar.add(getMenuHighScore());
						menu.setText("File");
						{
							exitButton = new JMenuItem();	
							menu.add(getMenuNewGame());
							menu.add(getMenuNetwork());
							menu.add(getMenuSeparator2());
							menu.add(getMenuSave());
							menu.add(getMenuLoad());							
							menu.add(getMenuSeparator1());
							menu.add(exitButton);
							exitButton.setAction(getExitAction());
							exitButton.setText("Exit");	
						}
					}
				}
			}
			pack();
			this.setSize(800, 650);
			this.setVisible(true);
			setLocationRelativeTo(null);
			this.setFont(new java.awt.Font("Tahoma",0,10));
			getContentPane().add(getBtnDie());
			getContentPane().add(getTxtTime());
			getContentPane().add(getLblDie());
			getContentPane().add(getTxtDie());
			getContentPane().add(getLblTurn());
			getContentPane().add(getTxtTurn());
			getContentPane().add(getPanelP1());
			getContentPane().add(getPanelP2());
			getContentPane().add(getPanelP3());
			getContentPane().add(getPanelP4());
			getContentPane().add(getLblP1());
			getContentPane().add(getLblP2());
			getContentPane().add(getLblP3());
			getContentPane().add(getLblP4());
		} catch(Exception e) {
			e.printStackTrace();
		}
		repaint();
	}

	/**
	 * If the menu item "Settings" is not initiated, initiate it,
	 * and return a reference.
	 * @return menuSettings
	 */
	private JMenu getMenuSettings() {
		if(menuSettings == null) {
			menuSettings = new JMenu();
			menuSettings.setText("Settings");
			menuSettings.add(getMenuSound());
			menuSettings.add(getRulesButton());
			menuSettings.add(getPlayerButton());
		}
		return menuSettings;
	}

	/**
	 * If the menu item "Help" is not initiated, initiate it,
	 * and return a reference. Add two items to it: "About" 
	 * and "Show Help".
	 * @return menuHelp
	 */
	private JMenu getMenuHelp() {
		if(menuHelp == null) {
			menuHelp = new JMenu();
			menuHelp.setText("Help");
			menuHelp.add(getMenuItemAbout());
			menuHelp.add(getMenuItemShowHelp());
		}
		return menuHelp;
	}


	/**
	 * If the menu sub-item "Show Help" is not initiated, initiate it,
	 * and return a reference. 
	 * @return menuItemShowHelp
	 */
	private JMenuItem getMenuItemShowHelp() {
		if(menuItemShowHelp == null) {
			menuItemShowHelp = new JMenuItem();
			menuItemShowHelp.setText("Show Help");
			menuItemShowHelp.setAction(getMenuHelpAction());
		}
		return menuItemShowHelp;
	}

	/**
	 * If the menu sub-item "Save" is not initiated, initiate it,
	 * and return a reference.
	 * @return menuSave
	 */
	private JMenuItem getMenuSave() {
		if(menuSave == null) {
			menuSave = new JMenuItem();
			menuSave.setText("Save");
		}
		return menuSave;
	}

	/**
	 * If the menu sub-item "Sound" is not initiated, initiate it,
	 * and return a reference. Also add two further sub-items to
	 * it; menuFX and menuMusic.
	 * @return menuSound
	 */
	private JMenu getMenuSound() {
		if(menuSound == null) {
			menuSound = new JMenu();
			menuSound.setText("Sound");
			menuSound.add(getMenuFX());
			menuSound.add(getMenuMusic());
		}
		return menuSound;
	}

	/**
	 * If the menu sub-item "menuFX" is not initiated, initiate it,
	 * and return a reference.
	 * @return menuFX
	 */
	private JCheckBoxMenuItem getMenuFX() {
		if(menuFX == null) {
			menuFX = new JCheckBoxMenuItem();
			menuFX.setText("FX");
		}
		return menuFX;
	}

	/**
	 * If the menu sub-item "menuMusic" is not initiated, initiate it,
	 * and return a reference.
	 * @return
	 */
	private JCheckBoxMenuItem getMenuMusic() {
		if(menuMusic == null) {
			menuMusic = new JCheckBoxMenuItem();
			menuMusic.setText("Music");
		}
		return menuMusic;
	}

	/**
	 * If the menu sub-item "Load" is not initiated, initiate it,
	 * and return a reference.
	 * @return menuLoad
	 */
	private JMenuItem getMenuLoad() {
		if(menuLoad == null) {
			menuLoad = new JMenuItem();
			menuLoad.setText("Load");
		}
		return menuLoad;
	}

	/**
	 * If the menu sub-item "New Game" is not initiated, initiate it,
	 * and return a reference.
	 * @return menuNewGame
	 */
	private JMenuItem getMenuNewGame() {
		if(menuNewGame == null) {
			menuNewGame = new JMenuItem();
			menuNewGame.setText("New Game");
			menuNewGame.setAction(getAbstractNewGame());
		}
		return menuNewGame;
	}

	/**
	 * If the menu sub-item "Network" is not initiated, initiate it,
	 * and return a reference.
	 * @return
	 */
	private JMenuItem getMenuNetwork() {
		if(menuNetwork == null) {
			menuNetwork = new JMenuItem();
			menuNetwork.setText("Network Game");
		}
		return menuNetwork;
	}

	/**
	 * If the menu sub-item "About" is not initiated, initiate it,
	 * and return a reference.
	 * @return
	 */
	private JMenuItem getMenuItemAbout() {
		if(menuItemAbout == null) {
			menuItemAbout = new JMenuItem();
			menuItemAbout.setText("jMenuItem1");
			menuItemAbout.setAction(getMenuAboutAction());
			menuItemAbout.setBounds(51, 19, 56, 19);
		}
		return menuItemAbout;
	}


	/**
	 * Associate an action with clicking the "About" option on the 
	 * About tab. 
	 * @return menuHelpAction
	 */
	private AbstractAction getMenuAboutAction() {
		if(menuAboutAction == null) {
			final View v = this;
			menuAboutAction = new AbstractAction("About Us", null) {
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent evt) {
					new About(v);
				}
			};
		}
		return menuAboutAction;
	}

	/**
	 * Associate an action with clicking the "Show Help" option on the 
	 * About tab. 
	 * @return menuHelpAction
	 */
	private AbstractAction getMenuHelpAction() {
		if(menuHelpAction == null) {
			menuHelpAction = new AbstractAction("Show Help", null) {
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent evt) {
					new Help();
				}
			};
		}
		return menuHelpAction;
	}

	/**
	 * Associate an action with exiting the application
	 * @return exitAction
	 */
	private AbstractAction getExitAction() {
		if(exitAction == null) {
			exitAction = new AbstractAction("Exit", null) {
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent evt) {
					disposeAll();
				}
			};
		}
		return exitAction;
	}

	/**
	 * Dispose of all Frames created by the application.
	 * This will terminate the application!
	 */
	private void disposeAll(){
		Frame[] allFrames = JFrame.getFrames();
		for(Frame f: allFrames)
			f.dispose();
	}

	/**
	 * Initiate the first menuSeparator if it is not initiated already
	 * @return menuSeparator1
	 */
	private JSeparator getMenuSeparator1() {
		if(menuSeparator1 == null) {
			menuSeparator1 = new JSeparator();
		}
		return menuSeparator1;
	}

	/**
	 * Initiate the second menuSeparator if it is not initialized already.
	 * @return menuSeparator2
	 */
	private JSeparator getMenuSeparator2() {
		if(menuSeparator2 == null) {
			menuSeparator2 = new JSeparator();
		}
		return menuSeparator2;
	}

	/**
	 * The button that throws the die.
	 * @return btnDie
	 */
	private JButton getBtnDie() {
		if(btnDie == null) {
			btnDie = new DieButton();
			btnDie.setText("Die");
			btnDie.setBounds(345, 266, 65, 60);            
			btnDie.setAction(getActionThrow());   
			btnDie.setToolTipText("Throw the Die!");
			btnDie.setMargin(new Insets(2,2,2,2));         
			btnDie.setIcon(new ImageIcon("img/die6.png"));
			btnDie.setFont(new java.awt.Font("Tahoma",0,11));
			btnDie.setPreferredSize(new java.awt.Dimension(65, 60));
		}
		return btnDie;
	}

	/**
	 * redraw the view from the current game state
	 */
	@Deprecated
	public void reDraw(){
		//TODO get the values from Model.java
		//txtDie.setText(""+model.getDieRoll());
		//txtTime.setText(""+model.getTurnTime());
		//txtTurn.setText(model.getCurrentPlayer());
	}

	/**
	 * Starts swing timers that schedule a turn change.
	 * Timers are used to delay the GUI update so that the player
	 * has time to see what is going on.
	 * @param p
	 */
	@Deprecated
	private void startTurnChange(String p){
		//new AfterThrowTimer(this, p);
		//timer = new TurnTimer(this, 2500);
	}

	/**
	 * Called by the timers.
	 * @param p
	 */
	@Deprecated
	public void changeTurn(String p){
		//$hide>>$
		txtDie.setText("");
		txtTime.setText("10");
		txtTurn.setText(p);
		btnDie.setEnabled(true);
		//$hide<<$
	}

	/**
	 * Decrements txtTime. The turn timer calls this every second.
	 */
	@Deprecated
	public void timerTick(){
		//$hide>>$
		txtTime.setText(""+(Integer.parseInt(txtTime.getText())-1));
		//$hide<<$
	}
	
	private AbstractAction getActionThrow() {
		if(actionThrow == null) {
			actionThrow = new AbstractAction("THROW", null) {
				private static final long serialVersionUID = 1L;

				public void actionPerformed(ActionEvent evt) {
					System.out.println(evt.getActionCommand());
					System.out.println(evt.getID());
					System.out.println(evt.getModifiers());
					System.out.println(evt.getSource());
					System.out.println(evt.getWhen());
					//btnDie.animate(); --currently handled in propertyChange
					m.handleEvent(evt);
				}
			};
		}
		return actionThrow;
	}
	
	private JMenu getMenuHighScore() {
		if(menuHighScore == null) {
			menuHighScore = new JMenu();
			menuHighScore.setText("High Score");
			menuHighScore.add(getButtonViewHighScore());
		}
		return menuHighScore;
	}

	private JMenuItem getButtonViewHighScore() {
		if(buttonViewHighScore == null) {
			buttonViewHighScore = new JMenuItem();
			buttonViewHighScore.setText("View High Score");
			buttonViewHighScore.setAction(getHighScoreButtonAction());
		}
		return buttonViewHighScore;
	}

	@SuppressWarnings("serial")
	private AbstractAction getHighScoreButtonAction() {
		if(highScoreButtonAction == null) {
			highScoreButtonAction = new AbstractAction("View High Score", null) {
				public void actionPerformed(ActionEvent evt) {
					new HighScoreView();
				}
			};
		}
		return highScoreButtonAction;
	}

	private JLabel getLabelTime() {
		if(labelTime == null) {
			labelTime = new JLabel();
			labelTime.setText("Time Left:");
			labelTime.setBounds(190, 11, 53, 16);
			labelTime.setFont(new java.awt.Font("Tahoma",0,10));
		}
		return labelTime;
	}
	
	private JMenuItem getRulesButton() {
		if(rulesButton == null) {
			rulesButton = new JMenuItem();
			rulesButton.setText("Rules");
			rulesButton.setAction(getRulesButtonAction());
		}
		return rulesButton;
	}
	
	private JMenuItem getPlayerButton() {
		if(playerButton == null) {
			playerButton = new JMenuItem();
			playerButton.setText("Player");
			playerButton.setAction(getPlayerButtonAction());
		}
		return playerButton;
	}
	
	@SuppressWarnings("serial")
	private AbstractAction getRulesButtonAction() {
		if(rulesButtonAction == null) {
			rulesButtonAction = new AbstractAction("Rules", null) {
				public void actionPerformed(ActionEvent evt) {
					new Rules();
				}
			};
		}
		return rulesButtonAction;
	}
	@SuppressWarnings("serial")
	private AbstractAction getPlayerButtonAction() {
		if(playerButtonAction == null) {
			playerButtonAction = new AbstractAction("Player", null) {
				public void actionPerformed(ActionEvent evt) {
					pSettings.setVisible(true);
				}
			};
		}
		return playerButtonAction;
	}
	
	private JTextField getTxtTime() {
		if(txtTime == null) {
			txtTime = new JTextField();
			txtTime.setText("Default");
			txtTime.setBounds(245, 7, 39, 21);
			txtTime.setEditable(false);
			txtTime.setBackground(Color.white);
			txtTime.setSize(45, 21);
		}
		return txtTime;
	}
	private JLabel getLblDie() {
		if(lblDie == null) {
			lblDie = new JLabel();
			lblDie.setText("Die:");
			lblDie.setBounds(471, 9, 23, 17);
			lblDie.setFont(new java.awt.Font("Tahoma",0,11));
		}
		return lblDie;
	}

	private JTextField getTxtDie() {
		if(txtDie == null) {
			txtDie = new JTextField();
			txtDie.setBounds(492, 8, 39, 20);
			txtDie.setText("Default");
			txtDie.setEditable(false);
			txtDie.setBackground(Color.white);
			txtDie.setSize(45, 20);
		}
		return txtDie;
	}

	private JLabel getLblTurn() {
		if(lblTurn == null) {
			lblTurn = new JLabel();
			lblTurn.setText("Turn:");
			lblTurn.setBounds(324, 10, 26, 15);
			lblTurn.setOpaque(true);
			lblTurn.setFont(new java.awt.Font("Tahoma",0,10));
			lblTurn.setBackground(new java.awt.Color(255,255,255));
		}
		return lblTurn;
	}

	private JTextField getTxtTurn() {
		if(txtTurn == null) {
			txtTurn = new JTextField();
			txtTurn.setBounds(350, 8, 60, 20);
			txtTurn.setMargin(new Insets(0,0,0,0));
			txtTurn.setText("Default");
			txtTurn.setEditable(false);
			txtTurn.setBackground(Color.white);
		}
		return txtTurn;
	}

	private JPanel getPanelP1() {
		if(panelP1 == null) {
			panelP1 = new StartBox(Color.red, "Red", m);
			panelP1.setBounds(10, 40, 150, 120);
			panelP1.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		}
		return panelP1;
	}

	private JPanel getPanelP2() {
		if(panelP2 == null) {
			panelP2 = new StartBox(Color.blue, "Blue", m);
			panelP2.setBounds(630, 40, 150, 120);
			panelP2.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		}
		return panelP2;
	}

	private JPanel getPanelP4() {
		if(panelP4 == null) {
			panelP4 = new StartBox(Color.yellow, "Yellow", m);
			panelP4.setBounds(10, 420, 150, 120);
			panelP4.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		}
		return panelP4;
	}

	private JPanel getPanelP3() {
		if(panelP3 == null) {
			panelP3 = new StartBox(Color.green, "Green", m);
			panelP3.setBounds(630, 420, 150, 120);
			panelP3.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		}
		return panelP3;
	}

	private JLabel getLblP1() {
		if(lblP1 == null) {
			lblP1 = new JLabel();
			lblP1.setText("Default");
			lblP1.setBounds(10, 20, 50, 15);
			lblP1.setSize(60, 15);
		}
		return lblP1;
	}

	private JLabel getLblP2() {
		if(lblP2 == null) {
			lblP2 = new JLabel();
			lblP2.setText("Default");
			lblP2.setBounds(630, 20, 50, 15);
			lblP2.setSize(60, 15);
		}
		return lblP2;
	}

	private JLabel getLblP4() {
		if(lblP4 == null) {
			lblP4 = new JLabel();
			lblP4.setText("Default");
			lblP4.setBounds(10, 400, 50, 15);
			lblP4.setSize(60, 15);
		}
		return lblP4;
	}

	private JLabel getLblP3() {
		if(lblP3 == null) {
			lblP3 = new JLabel();
			lblP3.setText("Default");
			lblP3.setBounds(630, 400, 50, 15);
			lblP3.setSize(60, 15);
		}
		return lblP3;
	}

	@Override
	public void paint(Graphics g){
		super.paint(g);
		//g.drawLine(200, 85, 200, 250); //menubar height == 45;
	}


	//-------------View part 2--------------------------------
	//$hide>>$
	Square[] squares = new Square[40];
	//Sizes
	private final int squareSide = 45;
	private final int firstSquareX = 80;
	private final int firstSquareY = 225;
	private final int spacingX = 10;
	private final int spacingY = 2;
	
	public EventBus getEventBus(){
		return m;
	}
	
	/**
	 * I'll go to hell for this method
	 * @author Mruzuki
	 */
	private void initSquares(){
		int x = firstSquareX, y = firstSquareY;

		//Phase one, top left section.
		for(int k = 0; k < 5; k++){
			Square s = new Square(x, y, k);
			this.getContentPane().add(s);
			s.setBounds(x, y, squareSide, squareSide);
			squares[k] = s;
			x += squareSide + spacingX;
		}
		x -= squareSide + spacingX;
		for(int l = 5; l < 9; l++){
			y -= squareSide + spacingY;
			Square s = new Square(x, y, l);
			this.add(s);
			squares[l] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}
		for(int i = 9; i < 10; i++){ //To bypass duplicate variable "s" problem.
			x += squareSide + spacingX;
			Square s = new Square(x, y, i);
			this.add(s);
			squares[i] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}

		//Phase two, top right section
		x += squareSide + spacingX;
		for(int k = 10; k < 15; k++){
			Square s = new Square(x, y, k);
			this.getContentPane().add(s);
			s.setBounds(x, y, squareSide, squareSide);
			squares[k] = s;
			y += squareSide + spacingY;
		}
		x += squareSide + spacingX;
		y -= squareSide + spacingY;
		for(int l = 15; l < 19; l++){
			Square s = new Square(x, y, l);
			this.add(s);
			s.setBounds(x, y, squareSide, squareSide);
			squares[l] = s;
			x += squareSide + spacingX;
		}
		x -= squareSide + spacingX;
		for(int i = 19; i < 20; i++){
			y += squareSide + spacingY;
			Square s = new Square(x, y, i);
			this.add(s);
			squares[i] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}

		//Phase three, bottom right section
		y += squareSide + spacingY;
		for(int k = 20; k < 25; k++){
			Square s = new Square(x, y, k);
			this.getContentPane().add(s);
			s.setBounds(x, y, squareSide, squareSide);
			squares[k] = s;
			x -= squareSide + spacingX;
		}
		x += squareSide + spacingX;
		for(int l = 25; l < 29; l++){
			y += squareSide + spacingY;
			Square s = new Square(x, y, l);
			this.add(s);
			squares[l] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}
		for(int i = 29; i < 30; i++){
			x -= squareSide + spacingX;
			Square s = new Square(x, y, i);
			this.add(s);
			squares[i] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}

		//Phase four, bottom left section
		x -= squareSide + spacingX;
		for(int k = 30; k < 35; k++){
			Square s = new Square(x, y, k);
			this.getContentPane().add(s);
			s.setBounds(x, y, squareSide, squareSide);
			squares[k] = s;
			y -= squareSide + spacingY;
		}
		y += squareSide + spacingY;
		for(int l = 35; l < 39; l++){
			x -= squareSide + spacingX;
			Square s = new Square(x, y, l);
			this.add(s);
			squares[l] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}
		for(int i = 39; i < 40; i++){
			y -= squareSide + spacingY;
			Square s = new Square(x, y, i);
			this.add(s);
			getContentPane().add(getLabelTime());
			squares[i] = s;
			s.setBounds(x, y, squareSide, squareSide);
		}

		//Fix the start squares
		squares[0].setColor(Color.red);
		squares[10].setColor(Color.blue);
		squares[20].setColor(Color.green);
		squares[30].setColor(Color.yellow);	

		//squares[15].add(new Piece(Color.black, squares[15]));
		addHomeRows();
	}
	
	private Square[][] homerows = new Square[4][4];
	
	private void addHomeRows(){
		for(int i = 0; i < 4; i++){
			int next = (i != 0)?(i*10)-1: 39;
			int x = squares[next].getX();
			int y = squares[next].getY();
			for(int j = 0; j < 4; j++){
				x += (i==0)?squareSide+spacingX:((i==2)?(-squareSide-spacingX):0);
				y += (i==1)?(squareSide+spacingY):((i==3)?(-squareSide-spacingY):0);
				Square s = new Square(x, y , 100 );
				this.add(s);
				s.setBounds(x, y, squareSide, squareSide);	
				s.setColor(squares[i*10].getColor());
				homerows[i][j] = s; //indexing
			}
		}
	}
	

	@Override
	public void propertyChange(PropertyChangeEvent arg0) {

		if(arg0.getPropertyName().equals("TURN")){
			this.txtTurn.setText(arg0.getNewValue().toString().split(" ")[0]);	
		}
		if(arg0.getPropertyName().equals("TIME")){
			this.txtTime.setText(arg0.getNewValue().toString());
		}
		if(arg0.getPropertyName().equals("DIE")){
			Integer dieFace = (Integer) arg0.getNewValue();
			this.txtDie.setText(dieFace.toString());
			if ((Integer)arg0.getOldValue() > -1){
				btnDie.setDieValue((Integer) arg0.getNewValue());
				btnDie.animate();
				
			}
		}
		if(arg0.getPropertyName().equals("RESET")){
			System.out.println("Reset");
			for(int i = 0; i < 4; i++)
				panelP1.popPiece();
			for(int i = 0; i < 4; i++)
				panelP2.popPiece();
			for(int i = 0; i < 4; i++)
				panelP3.popPiece();
			for(int i = 0; i < 4; i++)
				panelP4.popPiece();
			this.setVisible(false);
			this.getContentPane().removeAll();
			initGUI();
			initSquares();
			//this.setVisible(true);
			repaint();
		}
		if(arg0.getPropertyName().equals("P1HOME")){
			System.out.println("Home: "+ arg0.getNewValue());
			homerows[0][Math.abs((Integer)arg0.getNewValue())-1].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
		}
		if(arg0.getPropertyName().equals("P2HOME")){
			System.out.println("Home: "+ arg0.getNewValue());
			homerows[1][Math.abs((Integer)arg0.getNewValue())-1].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
		}
		if(arg0.getPropertyName().equals("P3HOME")){
			System.out.println("Home: "+ arg0.getNewValue());
			homerows[2][Math.abs((Integer)arg0.getNewValue())-1].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
		}
		if(arg0.getPropertyName().equals("P4HOME")){
			System.out.println("Home: "+ arg0.getNewValue());
			homerows[3][Math.abs((Integer)arg0.getNewValue())-1].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
		}
		if(arg0.getPropertyName().equals("P1PIECE")){
			if(arg0.getOldValue() == null){
				System.out.println("4. Inside P1Piece");
				System.out.println("5. Adding Piece: "+(Integer)arg0.getNewValue());
				panelP1.addPiece(new Piece(Color.red,(Integer)arg0.getNewValue()));
			}
			else if((Integer)arg0.getOldValue() == -1){
				Integer i = (Integer) arg0.getNewValue();
				String s = i.toString();
				//System.out.println("Adding piece: "+s);
				if(s.startsWith("0")) //Dunno if neccessary, used to verify that this is the correct player.
				squares[0].addPiece(panelP1.popPiece());
			}else {
				Piece p = squares[(Integer)arg0.getOldValue()].popPiece();
				squares[(Integer)arg0.getNewValue()].addPiece(p);
				//squares[(Integer)arg0.getOldValue()].removePiece((Integer)arg0.getOldValue());
			}
		}
		if(arg0.getPropertyName().equals("P2PIECE")){
			if(arg0.getOldValue() == null){
				panelP2.addPiece(new Piece(Color.blue,(Integer)arg0.getNewValue()));
			}else if((Integer)arg0.getOldValue() == -1){
				Integer i = (Integer) arg0.getNewValue();
				String s = i.toString();
				System.out.println(s);
				if(s.startsWith("1")) //Dunno if neccessary, used to verify that this is the correct player.
				squares[10].addPiece(panelP2.popPiece());
			}else {
				squares[(Integer)arg0.getNewValue()].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
				//squares[(Integer)arg0.getOldValue()].removePiece((Integer)arg0.getOldValue());
			}
		}
		if(arg0.getPropertyName().equals("P3PIECE")){
			if(arg0.getOldValue() == null){
				panelP3.addPiece(new Piece(Color.green,(Integer)arg0.getNewValue()));
			}else if((Integer)arg0.getOldValue() == -1){
				Integer i = (Integer) arg0.getNewValue();
				String s = i.toString();
				System.out.println(s);
				if(s.startsWith("2")) //Dunno if neccessary, used to verify that this is the correct player.
				squares[20].addPiece(panelP3.popPiece());
			}else {
				squares[(Integer)arg0.getNewValue()].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
				//squares[(Integer)arg0.getOldValue()].removePiece((Integer)arg0.getOldValue());
			}
		}
		if(arg0.getPropertyName().equals("P4PIECE")){
			if(arg0.getOldValue() == null){
				panelP4.addPiece(new Piece(Color.yellow,(Integer)arg0.getNewValue()));
			}else if((Integer)arg0.getOldValue() == -1){
				Integer i = (Integer) arg0.getNewValue();
				String s = i.toString();
				System.out.println(s);
				if(s.startsWith("3")) //Dunno if neccessary, used to verify that this is the correct player.
				squares[30].addPiece(panelP4.popPiece());
			}else {
				squares[(Integer)arg0.getNewValue()].addPiece(squares[(Integer)arg0.getOldValue()].popPiece());
				//squares[(Integer)arg0.getOldValue()].removePiece((Integer)arg0.getOldValue());
			}
		}
		if(arg0.getPropertyName().equals("P1NAME")){
			//this.lblP1.setText(arg0.getNewValue().toString().split(" ")[0]);
			lblP1.setText(arg0.getNewValue().toString());
			repaint();
			
		}
		if(arg0.getPropertyName().equals("P2NAME")){
			this.lblP2.setText(arg0.getNewValue().toString().split(" ")[0]);	
		}
		if(arg0.getPropertyName().equals("P3NAME")){
			this.lblP3.setText(arg0.getNewValue().toString().split(" ")[0]);	
		}
		if(arg0.getPropertyName().equals("P4NAME")){
			this.lblP4.setText(arg0.getNewValue().toString().split(" ")[0]);	
		}
		if(arg0.getPropertyName().equals("ERROR")){
			JOptionPane.showMessageDialog(this, arg0.getNewValue());	
		}
		repaint();
	}
	//$hide<<$
	
	@SuppressWarnings("serial")
	private AbstractAction getAbstractNewGame() {
		if(abstractNewGame == null) {
			abstractNewGame = new AbstractAction("New Game", null) {
				public void actionPerformed(ActionEvent evt) {
					m.handleEvent(evt);
				}
			};
		}
		return abstractNewGame;
	}

	/**
	 * This handler specifies what happens everytime the Model publishes something to
	 * the EventBus. The plan is that View should extract the new locations of player
	 * pieces from this, and simply move them accordingly.
	 * 
	 * More granularity can be added for more specific events.
	 */
	@Override
	public void onEvent(IModel event) {
		for(Integer[] pieces : event.getState().getPlayerLocations().values()) {
			// remove the piece from its current location, and put it somewhere else
			
		}
	}
	
	@EventTopicSubscriber(topic = "TURNTIMER")
	public void onEvent(String turn){
		System.out.println("Timer");
	}
}